机器学习目前非常擅长回答的问题类型是预测类。正如 Ajay Agrawal、Joshua Gans 和 Avi Goldfarb 在《预测机器》(Prediction Machine)一书中所说,“人工智能的新浪潮实际上并没有给我们带来智能,而是智能的一个关键组成部分——预测”。只要我们将问题转换为预测问题,机器学习就可以为我们实现各种奇迹。想把英语翻译成葡萄牙语?构建一个 ML 模型,基于英语句子预测葡萄牙语句子。想识别人脸?先构建一个用于预测图片中是否存在人脸的 ML 模型。想造一辆自动驾驶汽车?那就基于周围图像和传感器数据,用 ML 来预测车轮的方向以及的刹车和油门上的压力。
然而,ML 并不是万能的。它的确可以在非常严格的边界下创造奇迹,但如果新的数据与模型习惯的数据略有不同,它仍然会败得很惨。再举一个来自 《预测机器》(Prediction Machine) 的例子,“在许多行业中,低价格是与低销量相关的。比如在酒店行业,旅游旺季以外的客房价格低,而需求旺盛、酒店爆满时客房价格反而高。基于这样的数据训练的一个简单预测模型(naive prediction)可能会直接给出结论:提高客房售价会导致客房销量增加。”
ML 在这种逆因果问题上是出了名的糟糕。这类问题的特点,是要求我们描述“假如某事发生”之后的情况。经济学家们称之为反事实推理。假设我没有让商品保持当前价格不变,而是调整了一下价格,会发生什么?假设我不再继续我的低脂饮食,而是采用低糖饮食,又会怎么样?假设你在银行工作,负责提供信贷,你就必须得弄明白更改客户信用额度会对银行收入产生什么影响。又或者,假设你在当地政府工作,上级要求你搞搞清楚,怎么才能改善一下学校教育系统。你是要本着“数字知识时代的孩子怎么能没有平板”这样的想法,给每个孩子一人发一台平板电脑呢,还是说,其实建一个你小时候常去的那种图书馆就好?
每一个这样的问题的核心都是一个因果性的疑惑,等着我们去解答。因果问题不只贯穿在“如何提高营业额”之类的日常问题中。当我们面对极为私人且关键的抉择时,因果问题同样重要:我是否必须要上一所学费高昂的学校才能成功(受教育程度会影响收入吗)?外国移民是否会降低我找到工作的机会(移民是否会导致失业率上升)?面向穷人的社会救助手段(money transfer,低保资金转移)到底会不会降低犯罪率?不管你在哪个领域,你都很有可能不可避免地要回答某种形式的因果问题,不论是过去还是未来。不幸的是,这些问题并不能通过机器学习这种基于相关性的预测来直接解决。
这类因果问题比大多数人想象的要难回答得多。我们听说过很多次“相关性不代表因果关系”,“相关性不代表因果关系”,但真正去解释清楚为什么“相关性不代表因果关系”还是比较复杂的。不过解释这一概念正是本文“因果关系入门”主要任务
直觉上,我们模糊地知道为什么关联不是因果关系。 如果有人告诉你那些为学生提供平板电脑的学校比不提供平板电脑的学校学业表现更好,你可以很快指出原因:那很可能是因为那些配备平板电脑的学校更有钱。所以,即使没有平板电脑,他们的表现也会高于平均水平。因此,我们不能得出结论,说:在上课时为孩子们提供平板电脑会提高他们的学习成绩。 我们只能说:学校的平板电脑与更好的学业表现相关。
为了相较于简单的直觉更进一步,让我们首先建立一套符号。 这些符号将是我们用来谈论因果关系的共同语言。这种通用语可以让我们辨别出其他勇敢真诚的因果战士,并让我们和他们一起在接下来的战斗中用这种语言发出震天的战吼。
用 $T_i$ 代表个体i的处理介入量(treatment,“处理”偶尔也被称为“干预”)。
$$ T_i=\begin{cases} 1 \ \text{if unit i received the treatment}\\ 0 \ \text{otherwise}\\ \end{cases} $$在这里,我们并不要求“处理(治疗)”是药物或医学领域的某种概念。它只是一个术语,表示某些我们希望了解其效果的处理手段。 在刚才的案例中,处理就是给学生发平板电脑。顺便说一句,除了$T$,$D$ 也可以用来表示处理。
现在,我们将 $Y_i$ 称为个体 $i$ 的观察结果变量。
观察结果即是我们的目标变量。我们想知道“处理”究竟是否可以对“结果”产生影响。 在平板电脑问题中,观察结果变量就是学业表现。
因果推断的基本问题是:我们永远无法同时观察到同一个个体经过处理和未经处理的情况。 就好像我们面前有两条分岔的路,而我们只能知道我们选择了的那条路上有什么。 正如Robert Frost的诗:
两条路在黄树林中分岔,
很抱歉我不能同时走过这两条路
作为一名独行者,我驻足许久
尽我所能地往前看
直到在灌木旁蜿蜒消失;
为了解决这个问题,我们会在潜在结果方面展开很多讨论。它们之所以被称为“潜在的”结果是因为它们实际上并未发生。相反,它们表示在某些并未发生的处理条件下本可以发生什么。我们有时将发生了的潜在结果称为事实,而将未发生的潜在结果称为反事实。
符号方面,我们在这里使用一个额外的下标来标记处理:
$Y_{0i}$ 是个体 $i$ 未经处理时的潜在结果。
$Y_{1i}$ 是同一个个体 $i$ 经过处理后的潜在结果。
有时你可能会看到潜在结果以函数 $Y_i(t)$的形式来表示。所以: $Y_{0i}$ 可以写作 $Y_i(0)$,同时 $Y_{1i}$ 可以写作 $Y_i(1)$。在本系列文章中,我们绝大多数时候都会用$Y_{0i}$ 和$Y_{1i}$,即用下标来表示潜在结果是否经过处理。
回到刚才的例子,$Y_{1i}$ 是学生 $i$ 在配备平板电脑的学校中的学业表现。不论他/她究竟是不是真的在发平板的学校里上学,对于$Y_{1i}$变量来说都没有影响。无论现实怎样,$Y_{1i}$的值都是一样的。区别在于如果学生 $i$ 真的拿到了平板电脑,那我们就可以观察到 $Y_{1i}$。如果没拿到,我们可以观察到的量就变成了$Y_{0i}$。注意哪怕在第二种情况下,$Y_{1i}$ 仍然是有定义的,只是不能被观测到而已。即:$Y_{1i}$在这种情况下是一个反事实的潜在结果。
有了潜在结果,我们就可以来定义个体处理效应:
$Y_{1i} - Y_{0i}$
当然,由于因果推断基本问题的存在,我们永远无法知道个体的处理效应。因为对任何个体而言,我们都只能观察到两种潜在结果中的其中一种。那么就让我们把注意力先转移到一些比个体处理效应更容易估计的量上,比如平均处理效应。其定义如下。
$ATE = E[Y_1 - Y_0]$
其中,E[...]
是期望值。
除了平均处理效应之外,另一个更容易估计的量是处理组平均处理效应:
$ATT = E[Y_1 - Y_0 | T=1]$
先说一下,我知道我们不能同时看到两种潜在结果,但为了接下来的讨论,我们先假装我们可以看到。我们还收集了 4 所学校的数据,包括他们是否向学生提供了平板电脑,以及他们在几场年度学术测试中的分数。在这里,平板电脑是处理变量,所以如果学校向孩子们提供了平板电脑,则 $T=1$。 $Y$ 则是测试分数。
i | y0 | y1 | t | y | te | |
---|---|---|---|---|---|---|
0 | 1 | 500 | 450 | 0 | 500 | -50 |
1 | 2 | 600 | 600 | 0 | 600 | 0 |
2 | 3 | 800 | 600 | 1 | 600 | -200 |
3 | 4 | 700 | 750 | 1 | 750 | 50 |
这里的 $ATE$ 是最后一列的平均值,即处理效果的平均值:
$ATE=(-50 + 0 - 200 + 50)/4 = -50$
这意味平均来看,平板电脑会使学生的学习成绩降低 50 分。
而 $ATT$ 则是当$T=1$ 时,最后一列对应项的平均值:
$ATT=(- 200 + 50)/2 = -75$
也就是说,对于接受了处理的学校,平均来看,平板电脑使学生的学习成绩降低了 75 分。当然,现实中我们根本没办法知道这些数据。上面的表格在现实世界中看起来将是下面这样:
i | y0 | y1 | t | y | te | |
---|---|---|---|---|---|---|
0 | 1 | 500 | nan | 0 | 500 | nan |
1 | 2 | 600 | nan | 0 | 600 | nan |
2 | 3 | nan | 600 | 1 | 600 | nan |
3 | 4 | nan | 750 | 1 | 750 | nan |
“这肯定是不太理想,但把接受处理对象的平均值直接拿来,和没经过处理对象的平均值做差,难道不行吗?” 换句话说,我难道不能只计算 $ATE=(600+750)/2 - (500 + 600)/2 = 125$ 吗? 嗯……不行! 注意看,现在的结果和之前的完全不同。 而之所以产生这种区别,是因为你刚刚犯了最为严重的错误:将相关性误认为因果关系。 下一节来研究一下因果推断最容易犯得错误。
偏差即是令“关联”不同于“因果”关系的原因。我们来回顾一下上文平板电脑的例子。当面对声称“学校为学生提供平板电脑会让学生们考试成绩更好”的说法时,我们可以反驳说,即使没有平板电脑,这些学校也很可能会获得更高的考试分数,而那是因为他们可能比其他学校有更多的钱;因此,他们可以雇得起更好的教师,负担得起更好的教室,诸如此类。换句话说,经过处理的学校(发放平板电脑)与未经处理的学校没有可比性。
用潜在结果的符号表示这一点就是:处理组的$Y_0$ 与未处理组(untreated,在这个例子里等同于下文的对照组)的 $Y_0$ 不同。请注意!处理组的 $Y_0$ 是反事实的(因为对于处理组而言,可观测到的结果是$Y_1$)。尽管我们没办法观察到这个反事实结果,但我们可以针对它进行一些推理。在这个例子里,我们甚至可以基于我们对世界如何运作的理解更进一步。我们可以说,经过处理的学校的 $Y_0$ 很有可能大于未经处理学校的 $Y_0$。这是因为有能力为孩子提供平板电脑的学校也可以负担得起其他有助于提高考试成绩的因素。需要的话,稍微让这个思路在脑海里沉淀一下。习惯去以潜在结果的思维讨论问题肯定是需要一些时间的。
考虑到这一点,我们可以用非常简单的数学来说明为什么关联不是因果关系。关联是通过 $E[Y|T=1] - E[Y|T=0]$ 来衡量的。在我们的示例中,即是发放平板电脑的学校的平均考试成绩减去没有平板电脑的学校的平均考试成绩。另一方面,因果关系是由$E[Y_1 - Y_0]$衡量的。
为了理解它们之间的关系,让我们先用潜在结果来代表关联表达式中对应的项。对于处理组,观察到的结果是$Y_1$。对于未处理组,观察到的结果是$Y_0$。
$ E[Y|T=1] - E[Y|T=0] = E[Y_1|T=1] - E[Y_0|T=0] $
现在,让我们基于这个式子先加上再减去反事实结果$E[Y_0|T=1]$。它代表的是在没有处理的条件下,处理组的结果会是什么。
$ E[Y|T=1] - E[Y|T=0] = E[Y_1|T=1] - E[Y_0|T=0] + E[Y_0|T=1] - E[Y_0|T =1] $
最后,我们把式中各项重新排序,再把期望合并:
$ E[Y|T=1] - E[Y|T=0] = \underbrace{E[Y_1 - Y_0|T=1]}_{ATT} + \underbrace{\{ E[Y_0|T=1] - E[Y_0|T=0] \}}_{BIAS} $
这个简单的数学表达包罗了我们在因果问题中会遇到的所有困难。完全理解这个式子中的每一项都非常重要。 这个公式就类似某种值得我们珍视的核心准则,其真正的含义十分深邃,好比那些可以从一百种角度来解释的经文。事实上,我们可以更深入地研究一下这个式子。这个式子隐含了如下几点意思。首先,这个等式说明了为什么关联不是因果关系。正如我们所看到的,关联等于处理组处理效应加上一个偏差项。 偏差的真正含义是:在经过处理前,也就是当处理组和对照组(control group,即未处理组,控制组)都在未经处理的条件下,两者之间的差异。当有人跟我们说上课时候发平板电脑可以提高学习成绩时,我们现在可以准确地说出我们之所以怀疑这种说法的理由。那是因为我们认为这个例子中,$E[Y_0|T=0] < E[Y_0|T=1]$,也就是说,能为孩子提供平板电脑学校的学术表现相较于那些不能提供的学校,本身就更好,不论他们最终是否为学生提供了平板电脑。
现在你可以明白偏差之所以产生,正是因为许多我们无法控制的其他因素也在随着处理条件一起产生作用。因此,经过处理和未经处理的学校不仅在平板电脑这件事上有所不同。他们在学费、地点、师资等方面也有所不同……如果我们要证明课堂上提供平板电脑可以提高学习成绩,我们首先需要让发放了和没发放平板电脑的学校在其他各方面,平均而言,彼此相似。
现在我们了解了问题,让我们看看解决方案。我们也可以问自己:使关联等于因果关系的必要条件是什么。 如果 $E[Y_0|T=0] = E[Y_0|T=1]$,那么,关联就是因果关系! 仅仅是记住公式并不能算理解了这一点。这其中存在一个很强烈的直观论证。我们说$E[Y_0|T=0] = E[Y_0|T=1]$就是说处理组和对照组在处理前即具有可比性。或者说,在处理组不经处理的情况下,如果我们可以观察到它的$Y_0$,那么它的结果将与对照组的相同。这样在数学上,偏差项就会消失:
$ E[Y|T=1] - E[Y|T=0] = E[Y_1 - Y_0|T=1] = ATT $
此外,如果处理组和未处理组除了处理条件本身并无不同,即 $E[Y_0|T=0] = E[Y_0|T=1]$
我们则认为对处理组处理效应和和未处理组处理效应相同(因为两个组非常相似)。
$$ \begin{align} E[Y_1 - Y_0|T=1] &= E[Y_1|T=1] - E[Y_0|T=1] \\ &= E[Y_1|T=1] - E[Y_0|T=0] \\ &= E[Y|T=1] - E[Y|T=0] \end{align} $$不仅如此,$E[Y_1 - Y_0|T=1]=E[Y_1 - Y_0|T=0]$,仅仅因为处理组和和未处理组已经是可以互换的了。因此,在这种情况下,两个组结果平均数的差值成为了因果效应:
$ E[Y|T=1] - E[Y|T=0] = ATT = ATE $
因为这部分实在太重要了,我觉得我们有必要借助下面这几张好看的图把这部分再过一遍。如果我们在处理组和和未处理组之间做一个简单的平均比较,从图上来看就是这样的(蓝点没有接受处理,也就是平板电脑):
请注意两组之间的结果差异可能有两个原因:
真正的处理效果只有在我们拥有观察潜在结果时才能获得,如下左图所示。个体处理效果是:该个体可观测到的结果。与同一个体在受到反事实处理(例如:处理组对象未经处理)条件下的理论结果,二者之间的差。反事实结果以浅色表示。
右边的图描述了我们之前讨论过的偏差究竟是什么。如果我们让每个人都不接受处理,我们就会观察到偏差。在这种情况下,我们只剩下 $T_0$ 时的潜在结果。然后,我们能看到的就是处理组和未处理组有何不同。如果他们确实不同,则意味着有除处理条件之外的其他因素在起作用。这就是偏差,永远悄声无息地跟在真正的处理效果后面。
现在,为了方便对比,我们来看看偏差不存在的一种假设情况。假设平板电脑是随机分配给各个学校的。在这种情况下,贫富学校接受处理的机会是一样的。处理因素将很好地分布在所有学费范围内。
在这种情况下,处理和未处理之间的结果差异即是平均因果效应。发生这种情况是因为除了处理本身之外,处理组和未处理组之间没有其他差异来源。我们看到的所有差异都必须归因于处理。这种情况的另一种说法就是没有偏差。
如果我们将每个人都设置为不接受处理,只观察所有的 $Y_0$ 结果,我们将发现处理组和和未处理组之间没有差异。
这就是因果推理这个任务之所以艰巨的原因。我们真正要做的,就是找到各种巧妙的方法来消除偏差,使接受处理的和未接受处理的两组对象具有可比性,以便保证我们看到的所有差异都等于平均处理效果。 归根结底,因果推断需要排除所有妄想和误解的干扰,最终弄清楚世界究竟如何运转。明白了这一点,我们就可以继续学着去掌握一些格外强大的的武器,也就是那些用来消除偏差、识别因果关系的方法。
到目前为止,我们已经明白关联不是因果关系。最重要的是,我们已经明白了二者究竟哪里不一样,以及我们该如何让关联成为因果关系。为了方便我们把因果推理搞搞清楚,我们还引入了潜在结果符号。有了它,我们就可以将统计量视为两种潜在现实的结果:一种结果经过处理,另一种结果不经过处理。但是,不幸的是,我们只能测量其中之一,这就是因果推断的根本问题所在。
接下来,从随机试验的黄金标准开始,我们将学习一些估计因果效应的基本技巧。
资料来源
import pandas as pd
import numpy as np
from scipy.special import expit
import seaborn as sns
from matplotlib import pyplot as plt
from matplotlib import style
style.use("fivethirtyeight")
np.random.seed(123)
n = 100
tuition = np.random.normal(1000, 300, n).round()
tablet = np.random.binomial(1, expit((tuition - tuition.mean()) / tuition.std())).astype(bool)
enem_score = np.random.normal(200 - 50 * tablet + 0.7 * tuition, 200)
enem_score = (enem_score - enem_score.min()) / enem_score.max()
enem_score *= 1000
data = pd.DataFrame(dict(enem_score=enem_score, Tuition=tuition, Tablet=tablet))
plt.figure(figsize=(6,8))
sns.boxplot(y="enem_score", x="Tablet", data=data).set_title('ENEM score by Tablet in Class')
plt.show()
pd.DataFrame(dict(
i= [1,2,3,4],
y0=[500,600,800,700],
y1=[450,600,600,750],
t= [0,0,1,1],
y= [500,600,600,750],
te=[-50,0,-200,50],
))
i | y0 | y1 | t | y | te | |
---|---|---|---|---|---|---|
0 | 1 | 500 | 450 | 0 | 500 | -50 |
1 | 2 | 600 | 600 | 0 | 600 | 0 |
2 | 3 | 800 | 600 | 1 | 600 | -200 |
3 | 4 | 700 | 750 | 1 | 750 | 50 |
pd.DataFrame(dict(
i= [1,2,3,4],
y0=[500,600,np.nan,np.nan],
y1=[np.nan,np.nan,600,750],
t= [0,0,1,1],
y= [500,600,600,750],
te=[np.nan,np.nan,np.nan,np.nan],
))
i | y0 | y1 | t | y | te | |
---|---|---|---|---|---|---|
0 | 1 | 500.0 | NaN | 0 | 500 | NaN |
1 | 2 | 600.0 | NaN | 0 | 600 | NaN |
2 | 3 | NaN | 600.0 | 1 | 600 | NaN |
3 | 4 | NaN | 750.0 | 1 | 750 | NaN |
plt.figure(figsize=(10,6))
sns.scatterplot(x="Tuition", y="enem_score", hue="Tablet", data=data, s=70).set_title('ENEM score by Tuition Cost')
plt.show()